#define BIT 'O'
#define FOOD 'X'
#define START_BIT 5
#define LEFT 0
#define DOWN 1
#define RIGHT 2
#define UP 3

#define _XOPEN_SOURCE 500

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>

#include<time.h>
#include<ncurses.h>

struct bit{
	int x;
	int y;
	struct bit *next;
};

struct food{
	int x;
	int y;
};

struct bit *init_snake()
{
	struct bit *head=NULL;
	struct bit *temp=NULL;
	for(int i=0;i<START_BIT;i++)
	{
		temp=(struct bit *)malloc(sizeof(struct bit));
		temp->x=COLS/2+i;
		temp->y=LINES/2;
		temp->next=head;
		head=temp;
	}
	return head;

}

int hit_snake(struct bit *head, int x, int y)
{
	while(head)
	{
		if((head->x==x)&&(head->y==y))
			return 1;
		head=head->next;
	}
	return 0;
}

void new_food(struct food *new, struct bit *head)
{
	new->x=rand()%COLS;
	new->y=rand()%LINES;
	if(!hit_snake(head,new->x,new->y))
		mvaddch(new->y,new->x,FOOD);
	else
		new_food(new,head);
}

void draw_snake(struct bit *head)
{
	while(head)
	{
		mvaddch(head->y,head->x,BIT);
		head=head->next;
	}
}

int chdir_snake(int dir, int new)
{
	if(((new-2)!=dir)&&((new+2)!=dir)) return new;
	return dir;
}

struct bit *remlast_snake(struct bit *head)
{
	struct bit *temp;
	while(head->next->next)
		head=head->next;
	temp=head->next;
	mvaddch(temp->y,temp->x,' ');
	free(head->next);
	head->next=NULL;
	return head;
	
}

struct bit *drawfir_snake(struct bit *head, int dir)
{
	struct bit *temp;
	temp=(struct bit *) malloc(sizeof(struct bit));
	switch(dir)
	{
		case LEFT: temp->x=head->x-1;
			   temp->y=head->y;
			   break;
		case RIGHT: temp->x=head->x+1;
			    temp->y=head->y;
			    break;
		case UP: temp->y=head->y-1;
			 temp->x=head->x;
			 break;
		case DOWN: temp->y=head->y+1;
			   temp->x=head->x;
			   break;
	}
	if(temp->x>=COLS) temp->x=0;
	else if(temp->x<0) temp->x=COLS-1;
	if(temp->y>=LINES) temp->y=0;
	else if(temp->y<0) temp->y=LINES-1;
	mvaddch(temp->y,temp->x,BIT);
	temp->next=head;
	head=temp;
	return head;
}


int main()
{
	struct bit *snake = NULL;
	struct food foo;
	int dir=RIGHT;
	int score=0;
	WINDOW *win=NULL;

	srand(time(NULL));
	win=initscr();
	cbreak();
	noecho();
	nodelay(win,TRUE);
	keypad(win,TRUE);
	curs_set(0);
	snake=init_snake();
	draw_snake(snake);
	new_food(&foo,snake);

	while(!hit_snake(snake->next,snake->x,snake->y))
	{
		switch(getch())
		{
			case KEY_UP:
			case 'k': dir=chdir_snake(dir,UP);
				  break;
			case KEY_DOWN:
			case 'j': dir=chdir_snake(dir,DOWN);
				  break;
			case 'h':
			case KEY_LEFT: dir=chdir_snake(dir,LEFT);
				       break;
			case 'l':
			case KEY_RIGHT: dir=chdir_snake(dir,RIGHT);
					break;
			case 'q':
					return 0;
		}
		if(hit_snake(snake,foo.x,foo.y))
		{
			new_food(&foo,snake);
			score++;
		}
		else
			remlast_snake(snake);
		snake=drawfir_snake(snake,dir);
		refresh();
		usleep(100000);
	}
	char output[256];
	sprintf(output,"You suck, game over, score:%d",score);
	mvaddstr(LINES/2,COLS/2,output);

	refresh();

	sleep(3);
	endwin();
	return 0;
}


